<template>
  <div class="divbody">
    <div class="imgContainer" ref="imgContainer">
      <canvas
          :ref="'refmyCanvas'"
          class="canvasClass"
          :width="divWidth"
          :height="divHeight"
          @mousedown="canvasMouseDown"
          @mouseup="canvasMouseUp"
          @mousemove="canvasMouseMove"
      ></canvas>
      <img
          :id="'image'"
          :src="imageSrc"
          :ref="'refimage'"
          class="imgClass"
          @load="uploadImgLoad"
          v-show="false"
      />
    </div>
  </div>
</template>
<script>
export default {
  data() {
    return {
      divWidth: 0,
      divHeight: 0,
      imageSrc: 'https://image.baidu.com/search/detail?ct=503316480&z=0&ipn=false&word=%E5%A3%81%E7%BA%B8&step_word=&hs=0&pn=0&spn=0&di=7169026086108397569&pi=0&rn=1&tn=baiduimagedetail&is=0%2C0&istype=2&ie=utf-8&oe=utf-8&in=&cl=2&lm=-1&st=-1&cs=1660810865%2C2141524333&os=1910594475%2C1513894812&simid=1660810865%2C2141524333&adpicid=0&lpn=0&ln=1976&fr=&fmq=1526269427171_R&fm=&ic=0&s=undefined&hd=undefined&latest=undefined&copyright=undefined&se=&sme=&tab=0&width=&height=&face=undefined&ist=&jit=&cg=wallpaper&bdtype=0&oriquery=&objurl=https%3A%2F%2Fup.enterdesk.com%2Fedpic%2Fc5%2F3a%2Fe5%2Fc53ae5ec144c1d16105303c9d9bf68bb.jpg&fromurl=ippr_z2C%24qAzdH3FAzdH3Fooo_z%26e3Bjgpj61jfh_z%26e3Bv54AzdH3FktzitAzdH3Fmdlac-n98anl_z%26e3Bip4s&gsm=1e&rpstart=0&rpnum=0&islist=&querylist=&nojc=undefined',
      // canvas的配置部分
      c: '',
      cxt: '',
      canvasImg: '',
      imgWidth: 0, // img框的宽度
      imgHeight: 0, // img框的高度
      targetMarkIndex: -1, // 目标标注index
      params: {
        currentX: 0,
        currentY: 0,
        flag: false, // 用来判断在canvas上是否有鼠标down的事件，
        editFlag: false,
        editIndex: -1
      },
      // 目标类别list
      imageCategoryList: [],
      targetMarkArray: []
    }
  },
  mounted() {
    // 这里是进行初始化canvas的操作 myCanvas
    const self = this;
    try {
      self.c = self.$refs.refmyCanvas;
      self.canvasImg = self.$refs.refimage;
      self.cxt = self.c.getContext('2d');
      self.divWidth = self.$refs.imgContainer.offsetWidth;
      self.divHeight = self.$refs.imgContainer.offsetHeight;
    } catch (err) {
      console.log(err);
    }
    try {
      self.canvasOnDraw(self.imgWidth, self.imgHeight);
    } catch (err) {
      console.log(err);
    }
  },
  methods: {
    // 鼠标down事件
    canvasMouseDown(e) {
      this.params.flag = true;
      if (!e) {
        e = window.event;
        // 防止IE文字选中
        this.$refs.refmyCanvas.onselectstart = function() {
          return false;
        };
      }
      // 这里先判断一下，看是否是在有效数据，并且初始化参数
      if ((this.params.flag === true) && (this.params.editFlag === false)) {
        this.params.currentX = 0;
        this.params.currentY = 0;
        this.params.currentX = e.layerX;
        this.params.currentY = e.layerY;
        const dict1 = {
          x1: this.params.currentX, // 开始的x坐标
          y1: this.params.currentY, // 开始的y坐标
          x2: this.params.currentX, // 结束的x坐标
          y2: this.params.currentY, // 结束的y坐标
          flag: false, // 图片区域是否高亮,
          targetMarkValue: '', // 目标类别值
          wid: 0, // 矩形宽度
          hei: 0, // 矩形高度
          // final 是最终的框选的坐标值
          left: this.params.currentX,
          top: this.params.currentY,
          width: 0, // 矩形宽度
          height: 0, // 矩形高度
          finalX1: this.params.currentX,
          finalY1: this.params.currentY,
          finalX2: this.params.currentX,
          finalY2: this.params.currentY
        };
        this.targetMarkIndex = this.targetMarkIndex + 1;
        this.targetMarkArray.push(dict1);
      }
      // 执行渲染操作
      try {
        this.canvasOnDraw(this.imgWidth, this.imgHeight);
      } catch (err) {
        console.log(err);
      }
    },
    canvasMouseUp(e) {
      this.params.flag = false;
      try {
        this.canvasOnDraw(this.imgWidth, this.imgHeight);
      } catch (err) {
        console.log(err);
      }
    },
    canvasMouseMove(e) {
      if (e === null) {
        e = window.event;
      }
      if ((this.params.flag === true) && (this.params.editFlag === false)) {
        this.params.currentX = e.layerX;
        this.params.currentY = e.layerY;
        this.targetMarkArray[this.targetMarkIndex].x2 = this.params.currentX; // x1 值
        this.targetMarkArray[this.targetMarkIndex].y2 = this.params.currentY; // y1 值
        this.targetMarkArray[this.targetMarkIndex].wid = this.params.currentX - this.targetMarkArray[this.targetMarkIndex].x1; // 宽度值
        this.targetMarkArray[this.targetMarkIndex].hei = this.params.currentY - this.targetMarkArray[this.targetMarkIndex].y1; // 高度
      }
      // 执行渲染操作
      try {
        this.canvasOnDraw(this.imgWidth, this.imgHeight);
      } catch (err) {
        console.log(err);
      }
    },
    uploadImgLoad(e) {
      try {
        this.imgWidth = e.path[0].naturalWidth;
        this.imgHeight = e.path[0].naturalHeight;
        this.canvasOnDraw(this.imgWidth, this.imgHeight);
      } catch (err) {
        console.log(err);
      }
    },
    // 输入两个坐标值，判断哪个坐标值离左上角最近，其中特殊情况需要进行坐标查找工作
    findWhichIsFirstPoint(x1, y1, x2, y2) {
      // 首先判断x轴的距离谁更近
      if (x1 <= x2) {
        // 说明x1 比较小,接下来判断y谁更近
        if (y1 <= y2) {
          // 说明第一个坐标离得更近，直接顺序return就好
          return [x1, y1, x2, y2];
        } else {
          // 这里遇见一个奇葩问题，需要进行顶角变换
          return [x1, y2, x2, y1];
        }
      } else {
        // 这里是x1 大于 x2 的情况
        if (y2 <= y1) {
          return [x2, y2, x1, y1];
        } else {
          // y2 大于 y1 的情况, 这里需要做顶角变换工作
          return [x2, y1, x1, y2];
        }
      }
    },
    // canvas绘图部分
    canvasOnDraw(imgW = this.imgWidth, imgH = this.imgHeight) {
      const imgWidth = imgW;
      const imgHeight = imgH;
      this.divWidth = this.$refs.imgContainer.offsetWidth;
      this.divHeight = this.$refs.imgContainer.offsetHeight;
      this.cxt.clearRect(0, 0, this.c.width, this.c.height);
      // 当前的图片和现有的canvas容器之前的一个关系，是否有必要，我们后续做讨论
      var resPointList = this.changeOldPointToNewPoint(
          imgWidth,
          imgHeight,
          this.divWidth,
          this.divHeight
      );
      this.cxt.drawImage(
          this.canvasImg,
          0,
          0,
          imgWidth,
          imgHeight,
          0,
          0,
          resPointList[0],
          resPointList[1]
      );
      for (const index in this.targetMarkArray) {
        const x1 = this.targetMarkArray[App].x1;
        const y1 = this.targetMarkArray[App].y1;
        const x2 = this.targetMarkArray[App].x2;
        const y2 = this.targetMarkArray[App].y2;
        const wid = this.targetMarkArray[App].wid;
        const hei = this.targetMarkArray[App].hei;
        const FinalPointList = this.findWhichIsFirstPoint(
            (x1 * this.imgWidth) / resPointList[0],
            (y1 * this.imgHeight) / resPointList[1],
            (x2 * this.imgWidth) / resPointList[0],
            (y2 * this.imgHeight) / resPointList[1]
        );
        this.targetMarkArray[App].finalX1 = FinalPointList[0];
        this.targetMarkArray[App].finalY1 = FinalPointList[1];
        this.targetMarkArray[App].finalX2 = FinalPointList[2];
        this.targetMarkArray[App].finalY2 = FinalPointList[3];
        // 必须要有的字段
        this.targetMarkArray[App].left = this.targetMarkArray[App].finalX1;
        this.targetMarkArray[App].top = this.targetMarkArray[App].finalY1;
        this.targetMarkArray[App].width = this.targetMarkArray[App].finalX2 - this.targetMarkArray[App].finalX1;
        this.targetMarkArray[App].height = this.targetMarkArray[App].finalY2 - this.targetMarkArray[App].finalY1;
        // 调整四个顶角的函数，为了能让整体框选区域更好看
        const FinalPointListNow = this.findWhichIsFirstPoint(
            x1,
            y1,
            x2,
            y2
        );
        const tmpX1 = FinalPointListNow[0];
        const tmpY1 = FinalPointListNow[1];
        const tmpX2 = FinalPointListNow[2];
        const tmpY2 = FinalPointListNow[3];
        this.cxt.strokeStyle = '#FF6600';
        this.cxt.strokeRect(tmpX1, tmpY1, tmpX2 - tmpX1, tmpY2 - tmpY1);
        this.cxt.fillStyle = '#FF6600';
        this.cxt.font = '16px Arial';
        // canvas的标题部分
        this.cxt.fillText(parseInt(App) + 1, tmpX1, parseInt(tmpY1) - 6);
        // 这里是在处理高亮的地方
        this.cxt.fillStyle = 'rgba(255, 0, 0, 0.1)';
        this.cxt.fillRect(tmpX1, tmpY1, wid, hei);
        // 说明被点击了
        this.canvasDrowBorder(
            '#FF6600',
            tmpX1,
            tmpY1,
            tmpX2 - tmpX1,
            tmpY2 - tmpY1
        );
        this.canvasDrowInnerColor(
            'rgba(255, 0, 0, 0.3)',
            tmpX1,
            tmpY1,
            tmpX2 - tmpX1,
            tmpY2 - tmpY1
        );
      }
    },
    // canvas框选区域的内容颜色
    canvasDrowInnerColor(color, x, y, w, h) {
      this.cxt.fillStyle = color;
      this.cxt.fillRect(x, y, w, h);
    },
    // canvas框选区域的边框颜色
    canvasDrowBorder(color, x, y, w, h) {
      this.cxt.strokeStyle = color;
      this.cxt.strokeRect(x, y, w, h);
    },
    // 尺寸变换函数
    changeOldPointToNewPoint(imgw, imgH, canvasW, canvasH) {
      // 这里有个要求,先以宽度为准,然后再一步步调整高度
      var tmpW = canvasW;
      var tmpH = (tmpW * imgH) / imgw;
      // 如果转换之后的高度正好小于框的高度,则直接进行显示
      if (tmpH <= canvasH) {
        // 尺寸完美匹配
        return [tmpW, tmpH];
      } else {
        // 高度超出框了,需要重新调整高度部分
        tmpW = canvasW;
        tmpH = (tmpW * imgH) / imgw;
        var count = 1;
        var raise = 0.05;
        while (tmpH > canvasH || tmpW > canvasW) {
          tmpW = tmpW * (1 - raise * count);
          tmpH = (tmpW * imgH) / imgw;
        }
        return [tmpW, tmpH];
      }
    }
  }
}
</script>
<style lang="less" scoped>
.divbody {
  min-width: 640px;
  min-height: 480px;
}
.imgContainer {
  position: relative;
  width: 640px;
  height: 480px;
}
.canvasClass {
  position: absolute;
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 100%;
}
.imgClass {
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 100%;
}
</style>